#include "simple_module.h"

#define mybuf_size 100
#define BUFFS_CNT 1024 

char *my_buf[BUFFS_CNT];
int pos;
char vmalloced[BUFFS_CNT],kmalloced[BUFFS_CNT];

int simple_init(void) {
    int result;

    /* Rejestracja pliku w systemie proc */
    //create_proc_read_entry("simple", 0, NULL, simple_read_proc, NULL);

    /* Rejestracja urzadzenia */
    result = register_chrdev(simple_major, "mem_test", &simple_fops);
    if (result < 0) {
        printk("<1>Cannot register the /dev/simple device with major number: %d\n", simple_major);
        return result;
    }

    printk("Module created\n");
    return 0;
}

void simple_exit(void) {
    int i;
    /* Odrejestrowanie urzadzenia */
    unregister_chrdev(simple_major, "mem_test");

    /* Zwolnienie bufora */

    for(i = 0; i < BUFFS_CNT; i++) {
        if(kmalloced[i]) {
            printk("kfree at %d\n", i);
            kfree(my_buf[i]);
        }
        if(vmalloced[i]) {
            printk("vfree at %d\n", i);
            vfree(my_buf[i]);
        }
    }

    printk("Module removed\n");
}

int simple_open(struct inode *inode, struct file *filp) {
    return 0;
}

int simple_release(struct inode *inode, struct file *filp) {
    return 0;
}

ssize_t simple_read(struct file *filp, char *user_buf, size_t count, loff_t *f_pos) {
    printk("simple read called\n");
    return 0;
}


ssize_t simple_write(struct file *filp, const char *user_buf, size_t count, loff_t *f_pos) {
    // copy_from_user(to, from, size)
    int err;
    int repeat_num;
    int chunk;
    char tmp_buff[512];
    char command[128];
    char *cur;
    int i = 0, j = 0;

    err = copy_from_user(tmp_buff,user_buf,count);
    if(err) {
        printk("Error while copying from user\n");
    }

    sscanf(tmp_buff, "%s%d%d", command, &repeat_num, &chunk);

    printk("Command: %s, repeat num: %d, chunk size: %d\n", command, repeat_num, chunk);


    if(!strcmp("vmalloc", command)) {
        printk("Trying to vmallocing %d times\n", repeat_num);

        for(j = 0; j < repeat_num; j++) {
            while(i < BUFFS_CNT && (vmalloced[i] || kmalloced[i]))
                i++;
            if(i == BUFFS_CNT) {
                printk("Too many allocs!\n");
                break;
            }else{
                printk("Allocing at pos %d\n", i);
                my_buf[i] = vmalloc(chunk);
                vmalloced[i] = 1;
                memset(my_buf[i], 'a', chunk);
                i++;
            }
        }
    }else if(!strcmp("kmalloc", command)){
        printk("Trying to kmalloc %d times\n", repeat_num);

        for(j = 0; j < repeat_num; j++) {
            while(i < BUFFS_CNT && (vmalloced[i] || kmalloced[i]))
                i++;

            if(i == BUFFS_CNT) {
                printk("Too many allocs!\n");
                break;
            }else{
                printk("Allocing at pos %d\n", i);
                my_buf[i] = kmalloc(chunk, GFP_USER);
                kmalloced[i] = 1;
                memset(my_buf[i], 'a', chunk);
                i++;
            }
        }
    } else if(!strcmp("vfree", command)) {
        printk("vfreeing %d times\n", repeat_num);
        
        for(j = 0; j < repeat_num; j++) {
            while(i < BUFFS_CNT && !vmalloced[i])
                i++;

            if(i == BUFFS_CNT) {
                printk("No free possible\n");
                break;
            }else{
                printk("vfree at %d\n", i);
                vfree(my_buf[i]);
                vmalloced[i] = 0;
            }
        }
    }else if(!strcmp("kfree", command)) {
        printk("kfreeing %d times\n", repeat_num);

        for(j = 0; j < repeat_num; j++) {
            while(i < BUFFS_CNT && !kmalloced[i])
                i++;

            if(i == BUFFS_CNT) {
                printk("No free possible\n");
                break;
            }else{
                printk("kfree at %d\n", i);
                kfree(my_buf[i]);
                kmalloced[i] = 0;
            }
        }
    } else {
        printk("unknown command\n");
    }
    return count;
}

int simple_read_proc(char *page, char **start, off_t offset, int count, int *eof, void *data) 
{
    printk("read called\n");
    return 0;
}
